package com.bangcle.library.net;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class SSLManager {
    private final static String TAG = "SSLManager";
    protected final static char pwd[] = "123456".toCharArray();
    private static SSLSocketFactory mDefaultSSLSocketFactory=null,mSSLSocketFactory=null;
    private static HostnameVerifier mHostnameVerifier=null;
    private static void printCertificate(Certificate... certs) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {
        if(certs==null) return;
        for(Certificate cert:certs){
            if (!(cert instanceof X509Certificate)) {
                continue;
            }
            HttpLog.i(TAG, "##################################################################################");
            X509Certificate X509Cert = (X509Certificate) cert;
            HttpLog.i(TAG, "【所有者　】：" + X509Cert.getSubjectDN() + "");
            HttpLog.i(TAG, "【版本号　】：" + X509Cert.getVersion());
            HttpLog.i(TAG, "【序列号　】：" + X509Cert.getSerialNumber().toString(16));
            HttpLog.i(TAG, "【类型　　】：" + X509Cert.getType());
            HttpLog.i(TAG, "【签发者　】：" + X509Cert.getIssuerDN());
            HttpLog.i(TAG, "【有效期　】：" + X509Cert.getNotBefore());
            HttpLog.i(TAG, "【签名算法】：" + X509Cert.getSigAlgName());
            HttpLog.i(TAG, "【公钥　　】：" + X509Cert.getPublicKey());
            HttpLog.i(TAG, "##################################################################################");
        }
    }
    protected static void println(KeyStore ks, char[] pwd) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException {
        Enumeration<String> aliases = ks.aliases();
        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            printCertificate(ks.getCertificate(alias));
        }
    }
    /**
     * 载入信任证书库
     */
    protected static KeyStore buildTrustKeyStore() throws IOException, GeneralSecurityException {
        BufferedInputStream bis = new BufferedInputStream(SSLManager.class.getResourceAsStream("openssl/httptrust.pem"));
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(null);
        while (bis.available() > 0) {
            Certificate cert = cf.generateCertificate(bis);
            ks.setCertificateEntry("Trust-Certificate-" + ks.size(), cert);
        }
        bis.close();
        HttpLog.i(TAG, "======================== TrustKeyStore(" + ks.size() + ") ========================");
        println(ks, null);
        return ks;
    }

    /**
     * 载入个人证书库(含用户公钥、私钥、证书等)
     */
    protected static KeyStore buildPrivateStore() throws IOException, GeneralSecurityException {
        InputStream fis = SSLManager.class.getResourceAsStream("openssl/httpclient.p12");
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(fis, pwd);
        fis.close();
        HttpLog.i(TAG, "======================== PrivateKeyStore(" + ks.size() + ") ========================");
        println(ks, pwd);
        return ks;
    }

    /**
     * 创建带信任库的SSLSocketFactory（验证服务器证书的合法性）
     */
    public static SSLSocketFactory buildSSLSocketFactory() throws Exception {
        if(mSSLSocketFactory!=null) return mSSLSocketFactory;
        // 初始化个人证书管理器
        KeyManagerFactory kmFact = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmFact.init(SSLManager.buildPrivateStore(), pwd);
        KeyManager[] kms = kmFact.getKeyManagers();
        // 初始化信任管理器
        TrustManagerFactory tmFact = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmFact.init(SSLManager.buildTrustKeyStore());
        TrustManager[] tms = tmFact.getTrustManagers();
        // 初始化SSLContext
        SSLContext sslContext = SSLContext.getInstance("SSL");        
        sslContext.init(kms, tms, null);
        mSSLSocketFactory = sslContext.getSocketFactory();
        return mSSLSocketFactory;
    }
    /**
     * 创建默认的SSLSocketFactory（不验证服务器证书的合法性）
     */
    public static SSLSocketFactory buildDefaultSSLSocketFactory() throws Exception {
        if(mDefaultSSLSocketFactory!=null) return mDefaultSSLSocketFactory;
        X509TrustManager trustAllCerts=new X509TrustManager(){
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {            
            }
            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {            
            }
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            } 
        };
        // 初始化SSLContext
        SSLContext sslContext = SSLContext.getInstance("SSL");        
        sslContext.init(null, new X509TrustManager[]{trustAllCerts}, null);
        mDefaultSSLSocketFactory = sslContext.getSocketFactory();
        return mDefaultSSLSocketFactory;
    }
    public static HostnameVerifier buildHostnameVerifier() throws Exception {
        if(mHostnameVerifier!=null) return mHostnameVerifier;
        mHostnameVerifier=new HostnameVerifier() {
            @Override
            public boolean verify(String host, SSLSession mSession) {
                HttpLog.i(TAG, "[Verify]: Host=" + host + "; SSL Session=" + mSession);
                return true;
            }
        };
        return mHostnameVerifier;
    }
    //初始化
    public static void initSSL(HttpURLConnection conn) {
        try {
            if(!(conn instanceof HttpsURLConnection)) return;
            //使用证书信任库验证服务器，防止网路劫持攻击
            ((HttpsURLConnection)conn).setSSLSocketFactory(SSLManager.buildSSLSocketFactory());
            ((HttpsURLConnection)conn).setHostnameVerifier(SSLManager.buildHostnameVerifier());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
